package cn.bitkit.tools.net;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.List;

import cn.bitkit.tools.common.IOUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.sshd.client.SshClient;
import org.apache.sshd.client.channel.ChannelExec;
import org.apache.sshd.client.channel.ClientChannelEvent;
import org.apache.sshd.client.session.ClientSession;
import org.apache.sshd.sftp.client.SftpClient;
import org.apache.sshd.sftp.client.SftpClient.OpenMode;
import org.apache.sshd.sftp.client.SftpClientFactory;

/**
 * 	ssh连接
 * @author changbo
 *
 */
@Slf4j
public class SshHelper {
	
	private SshClient client;
	private ClientSession session;
	private final long timeout = 10000L;

    public static SshHelper getSshHelper(){
    	return new SshHelper();
    }
    
    public SshHelper connect(String ip, int port, String username, String password){
    	return connect(ip, port, username, password, false, null, 0);
    }

	@SneakyThrows
    public SshHelper connect(String ip, int port, String username, String password, boolean isProxy, String proxyIp, int proxyPort){
		SshClient client = SshClient.setUpDefaultClient();
		client.start();
		session = client.connect(username, ip, port).getClientSession();
		session.addPasswordIdentity(password);
		if (!session.auth().verify(timeout).isSuccess()) {
			log.error("auth fail");
		}
    	return this;
    }

	@SneakyThrows
    public String execute(String cmd){
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		ChannelExec channel = session.createExecChannel(cmd);
		channel.setOut(out);
		if (!channel.open().verify(timeout).isOpened()) {
			throw new Exception("open faild");
		}
		List<ClientChannelEvent> list = new ArrayList<>();
		list.add(ClientChannelEvent.CLOSED);
		channel.waitFor(list, timeout);
		channel.close();
		return out.toString();
    }

	@SneakyThrows
    public void upload(String remoteFile, InputStream input){
		SftpClient client = SftpClientFactory.instance().createSftpClient(session);
		FileChannel channel = client.openRemoteFileChannel(remoteFile, OpenMode.Write);
		IOUtil.write(input, channel);
    }

	@SneakyThrows
    public void download(String remoteFile, OutputStream output){
		SftpClient client = SftpClientFactory.instance().createSftpClient(session);
		FileChannel channel = client.openRemoteFileChannel(remoteFile, OpenMode.Read);
		IOUtil.write(channel, output);
    }

    public void close(){
		IOUtil.close(session);
		IOUtil.close(client);
    }
    
}
